#include "StdAfx.h"
#include "DiamondUnit.h"
#include "MyRectTracker.h"
#include "DataFlow.h"
#include "ArrowUnit.h"
#include <queue>
CDiamondUnit::CDiamondUnit(void)
{
	m_Tracker=new CMyRectTracker();
	((CMyRectTracker*)m_Tracker)->m_nStyle=CRectTracker::resizeOutside | CRectTracker::dottedLine;
}

CDiamondUnit::~CDiamondUnit(void)
{
	delete m_Tracker;
}
void CDiamondUnit::Preview(CDC* pDC)
{
	CPen pen;
	pen.CreatePen(PS_DOT,1,RGB(0,0,0));
	CPen* oldpen=pDC->SelectObject(&pen);
	CPoint p[4];

	p[0].x = (m_BeginPoint.x + m_EndPoint.x)/2;
	p[0].y = m_BeginPoint.y;
	p[1].x = m_BeginPoint.x;
	p[1].y = (m_BeginPoint.y + m_EndPoint.y)/2;
	p[2].y = m_EndPoint.y;
	p[2].x = (m_BeginPoint.x + m_EndPoint.x)/2;
	p[3].x = m_EndPoint.x;
	p[3].y = (m_BeginPoint.y + m_EndPoint.y)/2;

	pDC->Polygon(p,4);

	pDC->SelectObject(oldpen);
}
void CDiamondUnit::Draw(CDC* pDC)
{
	CPen pen;
	pen.CreatePen(PS_SOLID,1,RGB(0,0,0));
	CPen* oldpen=pDC->SelectObject(&pen);
	CPoint p[4];

	p[0].x = (m_BeginPoint.x + m_EndPoint.x)/2;
	p[0].y = m_BeginPoint.y;
	p[1].x = m_BeginPoint.x;
	p[1].y = (m_BeginPoint.y + m_EndPoint.y)/2;
	p[2].y = m_EndPoint.y;
	p[2].x = (m_BeginPoint.x + m_EndPoint.x)/2;
	p[3].x = m_EndPoint.x;
	p[3].y = (m_BeginPoint.y + m_EndPoint.y)/2;

	pDC->Polygon(p,4);
	pDC->SelectObject(oldpen);
}
BOOL CDiamondUnit::OnHitTest(CPoint* point)
{
	CRgn rgn;
	CPoint p[4];

	p[0].x = (m_BeginPoint.x + m_EndPoint.x)/2;
	p[0].y = m_BeginPoint.y;	
	p[1].x = m_BeginPoint.x;
	p[1].y = (m_BeginPoint.y + m_EndPoint.y)/2;
	p[2].x = (m_BeginPoint.x + m_EndPoint.x)/2;
	p[2].y = m_EndPoint.y;
	p[3].x = m_EndPoint.x;
	p[3].y = (m_BeginPoint.y + m_EndPoint.y)/2;

	rgn.CreatePolygonRgn(p, 4, ALTERNATE);
	if (rgn.PtInRegion(*point))
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

void CDiamondUnit::Save(CArchive& out)
{
	out<<CString("Diamond");
	CUnit::Save(out);
}
void CDiamondUnit::Load(CArchive& in)
{
	CUnit::Load(in);
}
void CDiamondUnit::Track(CWnd* parent,CPoint* point)
{
	m_Tracker->Track(parent,*point);
	CPoint old_begin=m_BeginPoint;
	CPoint old_end=m_EndPoint;
	if (m_BeginPoint!=((CMyRectTracker*)m_Tracker)->m_rect.TopLeft() || m_EndPoint!=((CMyRectTracker*)m_Tracker)->m_rect.BottomRight())
	{
		CUnit* father=theApp.m_UnitManager->GetFather(this);
		father->DeleteChild(this);
		m_BeginPoint=((CMyRectTracker*)m_Tracker)->m_rect.TopLeft();
		m_EndPoint=((CMyRectTracker*)m_Tracker)->m_rect.BottomRight();
		theApp.m_UnitManager->AddShape(this);
	}
	TrackBroad(old_begin,old_end);
}

BOOL CDiamondUnit::ContainUnit(CUnit* unit)
{
	int count=0;
	CPoint* point=unit->GetVertex(count);
	if (count==2)
	{
		delete point;
		return FALSE;
	}
	CRgn rgn;
	CPoint p[4];
	p[0].x=m_BeginPoint.x;
	p[0].y=(m_BeginPoint.y+m_EndPoint.y)/2;
	p[1].x=(m_BeginPoint.x+m_EndPoint.x)/2;
	p[1].y=m_BeginPoint.y;
	p[2].x=m_EndPoint.x;
	p[2].y=(m_BeginPoint.y+m_EndPoint.y)/2;
	p[3].x=(m_BeginPoint.x+m_EndPoint.x)/2;
	p[3].y=m_EndPoint.y;
	rgn.CreatePolygonRgn(p,4,ALTERNATE);
	for (int i=0;i<count;i++)
	{		
		if (!rgn.PtInRegion(point[i]))
		{
			delete point;
			return FALSE;
		}
	}
	delete point;
	return TRUE;
}
CPoint* CDiamondUnit::GetVertex(int &count)
{
	CPoint* p=new CPoint[4];
	p[0].x=m_BeginPoint.x;
	p[0].y=(m_BeginPoint.y+m_EndPoint.y)/2;
	p[1].x=(m_BeginPoint.x+m_EndPoint.x)/2;
	p[1].y=m_BeginPoint.y;
	p[2].x=m_EndPoint.x;
	p[2].y=(m_BeginPoint.y+m_EndPoint.y)/2;
	p[3].x=(m_BeginPoint.x+m_EndPoint.x)/2;
	p[3].y=m_EndPoint.y;
	count=4;
	return p;
}
void CDiamondUnit::AttachTracker()
{
	((CMyRectTracker*)m_Tracker)->m_rect.SetRect(m_BeginPoint,m_EndPoint);
}

BOOL CDiamondUnit::AllowText()
{
	return FALSE;
}
void CDiamondUnit::AddLink(LinkArrow link)
{
	m_LinkList->push_back(link);
}
void CDiamondUnit::RemoveLink(LinkArrow link)
{
	LinkItr it;
	for (it=m_LinkList->begin();it!=m_LinkList->end();it++)
	{
		LinkArrow la=*it;
		if (la.cp==link.cp && la.unit->Equals(link.unit))
		{
			m_LinkList->erase(it);
			break;
		}
	}
}
void CDiamondUnit::TrackBroad(CPoint old_begin,CPoint old_end)
{
	int tmpx=old_begin.x;
	int tmpy=old_begin.y;
	int width=old_end.x-old_begin.x;
	int height=old_end.y-old_begin.y;
	int begin_dx=old_begin.x-((CMyRectTracker*)m_Tracker)->m_rect.TopLeft().x;
	int begin_dy=old_begin.y-((CMyRectTracker*)m_Tracker)->m_rect.TopLeft().y;
	int end_dx=old_end.x-((CMyRectTracker*)m_Tracker)->m_rect.BottomRight().x;
	int end_dy=old_end.y-((CMyRectTracker*)m_Tracker)->m_rect.BottomRight().y;

	if (begin_dx!=0 || begin_dy!=0 || end_dx!=0 || end_dy!=0)
	{
		/*
		CUnit* container=theApp.m_UnitManager->GetContainer(theApp.m_UnitManager->m_ShapeRoot,this);
		if (container!=NULL && container!=theApp.m_UnitManager->m_ShapeRoot)
		{
		vector<LinkArrow>::iterator it=m_LinkList->begin();
		while (m_LinkList->size()>0)
		{
		LinkArrow* arrow=&(*it);
		((CArrowUnit*)arrow->unit)->m_BeginUnit->RemoveLink(*arrow);
		((CArrowUnit*)arrow->unit)->m_EndUnit->RemoveLink(*arrow);
		theApp.m_UnitManager->Delete(arrow->unit);
		it=m_LinkList->begin();
		}
		}*/


	}
	int w=m_EndPoint.x-m_BeginPoint.x;
	int h=m_EndPoint.y-m_BeginPoint.y;
	float zoom_width=(float)w/(float)width;
	float zoom_height=(float)h/(float)height;
	if (w!=width || h!=height)
	{		
		CUnitQue unit_queue;
		CUnitItr i;
		for(i=m_ChildList->begin();i!=m_ChildList->end();i++)
		{
			CUnit* unit=*i;
			unit_queue.push(unit);
		}
		while (!unit_queue.empty())
		{
			CUnit* unit=unit_queue.front();
			unit_queue.pop();
			int bx=unit->m_BeginPoint.x-tmpx;
			int by=unit->m_BeginPoint.y-tmpy;
			int unit_w=unit->m_EndPoint.x-unit->m_BeginPoint.x;
			int unit_h=unit->m_EndPoint.y-unit->m_BeginPoint.y;
			unit->m_BeginPoint.x=m_BeginPoint.x+bx*zoom_width;
			unit->m_BeginPoint.y=m_BeginPoint.y+by*zoom_height;
			unit->m_EndPoint.x=unit->m_BeginPoint.x+unit_w*zoom_width;
			unit->m_EndPoint.y=unit->m_BeginPoint.y+unit_h*zoom_height;
			for(i=unit->m_ChildList->begin();i!=unit->m_ChildList->end();i++)
			{
				unit_queue.push(*i);
			}
		}	
	}
	else
	{
		CUnitQue unit_queue;
		CUnitItr i;
		for(i=m_ChildList->begin();i!=m_ChildList->end();i++)
		{
			CUnit* unit=*i;
			unit_queue.push(unit);
		}
		while (!unit_queue.empty())
		{
			CUnit* unit=unit_queue.front();
			unit_queue.pop();
			unit->m_BeginPoint.x-=begin_dx;
			unit->m_BeginPoint.y-=begin_dy;
			unit->m_EndPoint.x-=end_dx;
			unit->m_EndPoint.y-=end_dy;
			for(i=unit->m_ChildList->begin();i!=unit->m_ChildList->end();i++)
			{
				unit_queue.push(*i);
			}
		}	
	}
	int begin_off_x=m_BeginPoint.x-old_begin.x;
	int begin_off_y=m_BeginPoint.y-old_begin.y;
	int end_off_x=m_EndPoint.x-old_end.x;
	int end_off_y=m_EndPoint.y-old_end.y;
	LinkItr it;
	int size=(int)m_LinkList->size();
	for (int i=0;i<size;i++)
	{
		LinkArrow* link=&(*m_LinkList)[i];
		if (begin_off_x!=0 || begin_off_y!=0 || end_off_x!=0 || end_off_y!=0)
		{
			if (link->cp.x==old_begin.x)
			{
				((CArrowUnit*)(link->unit))->LinkMove(link->cp,m_BeginPoint.x,(m_BeginPoint.y+m_EndPoint.y)/2);
				link->cp.x=m_BeginPoint.x;
				link->cp.y=(m_BeginPoint.y+m_EndPoint.y)/2;
			}
			if (link->cp.x==old_end.x)
			{
				((CArrowUnit*)(link->unit))->LinkMove(link->cp,m_EndPoint.x,(m_BeginPoint.y+m_EndPoint.y)/2);
				link->cp.x=m_EndPoint.x;
				link->cp.y=(m_BeginPoint.y+m_EndPoint.y)/2;
			}
			if (link->cp.y==old_end.y)
			{
				((CArrowUnit*)(link->unit))->LinkMove(link->cp,(m_BeginPoint.x+m_EndPoint.x)/2,m_EndPoint.y);
				link->cp.x=(m_BeginPoint.x+m_EndPoint.x)/2;
				link->cp.y=m_EndPoint.y;
			}
			if (link->cp.y==old_begin.y)
			{
				((CArrowUnit*)(link->unit))->LinkMove(link->cp,(m_BeginPoint.x+m_EndPoint.x)/2,m_BeginPoint.y);
				link->cp.x=(m_BeginPoint.x+m_EndPoint.x)/2;
				link->cp.y=m_BeginPoint.y;
			}
		}
	}
}
void CDiamondUnit::DistachTracker()
{
	((CRectTracker*)m_Tracker)->m_rect.SetRect(0,0,0,0);
}